package me.webase.dao;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import me.webase.util.json.JSONArray;
import me.webase.util.json.JSONException;
import me.webase.util.json.JSONObject;

import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.Query;
import org.hibernate.Session;


/**
 * json 自动生成Hql
 * 
 */
public class FormatHql {
	/**
	 * 值索引,
	 */
	private int valueIndex = 0;
	/**
	 * 需要加入的值列表
	 */
	private List<Object> valueList = new ArrayList<Object>();
	private Session session;
	/**
	 * 用于拼接sql字符串
	 */
	private StringBuilder sb = new StringBuilder();
	
	private static final String  SINGLEVALUE= "singleValue";
	private static final String  LISTVALUE= "listValue";
	private static final String  BETWEENVALUE= "betweenValue";
	private static final String  PROPERTY= "property";
	private static final String  CONDITION= "condition";
	private static final String  VALUE_INDEX = ":value_index_";
	private static final String  VALUE = "value_index_";
	private static final String  END = "$END$";
	
	private Class clazz;
	
	private Object unity;
	
	public FormatHql(Class clazz,Session session,String json){
		this.session = session;
		this.clazz = clazz;
		
		try {
			unity = clazz.newInstance();
			JSONArray jArr = new JSONArray(json);
			int length = jArr.length();
			sb.append("from ");
			sb.append(clazz.getSimpleName());
			if(length > 0){
				sb.append(" where");
				for(int i=0;i<length;i++){
					andSql(sb,jArr.getJSONArray(i));
				}
				System.out.println(sb.toString());
				if(sb.indexOf(END) > 0){
					//删除 where
					sb.delete(sb.length()-5-END.length()*length, sb.length());
				} else {
					//删除   “ or ”
					sb.delete(sb.length()-3, sb.length()-1);
				}
			}
			
			
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public Query createQuery(){
		System.out.println(sb.toString());
		Query query = session.createQuery(sb.toString());
		for(int i = 0;i<valueList.size();i++){
			System.out.println(valueList.get(i));
			query.setParameter(VALUE+i, valueList.get(i));
		}
		return query;
	}
	
	public Query createCountQuery(){
		sb.insert(0,"select count(*) ");
		System.out.println(sb.toString());
		Query query = session.createQuery(sb.toString());
		for(int i = 0;i<valueList.size();i++){
			System.out.println(valueList.get(i));
			query.setParameter(VALUE+i, valueList.get(i));
		}
		return query;
	}
	
	public long getCount(){
		return (long)createCountQuery().list().get(0);
	}
	
	/**
	 * 解析一组and  Sql 语句
	 * @param jArr
	 */
	private void andSql(StringBuilder sb,JSONArray jArr){
	
		
		int length = jArr.length();
		
		if(length == 0){
			sb.append(END);
			return;
		}
		sb.append("(");
		for(int i=0;i<length;i++){
			try {
				JSONObject o = jArr.getJSONObject(i);
				if(o.has(SINGLEVALUE)){
					singleValue(sb, o);
				} else if(o.has(LISTVALUE)){
					listValue(sb, o);
				} else if(o.has(BETWEENVALUE)){
					betweenValue(sb, o);
				} else {
					withoutValue(sb, o);
				}
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		sb.delete(sb.length()-4,sb.length()-1);
		sb.append(")");
		sb.append(" or ");
	}
	
	/**
	 * json 条件样式
	 * 	[{property:'name',condition:' is null '},
	 *  {property:'name',condition:' is not null '},
	 *  {property:'name',condition:' = ', singleValue:'zhou'},
	 *  {property:'age',condition:' in ',listValue:[16,17,18]},
	 *  {property:'age',condition:' not in ',listValue:[16,17,18]},
	 *  {property:'age',condition:' between ',betweenValue:[18,23]},
	 *  {property:'age',condition:' not between ',betweenValue:[18,23]}]
	 * @param jsonCondition
	 * @throws JSONException 
	 */
	private void withoutValue(StringBuilder sb,JSONObject jObj) throws JSONException{
		sb.append(jObj.getString(PROPERTY));
		sb.append(jObj.getString(CONDITION));
		sb.append(" and ");
	}
	
	private void singleValue(StringBuilder sb,JSONObject jObj) throws JSONException{
		String propertyName = jObj.getString(PROPERTY);
		sb.append(propertyName);
		sb.append(jObj.getString(CONDITION));
		sb.append(VALUE_INDEX+valueIndex);
		sb.append(" and ");
		valueList.add(getValue(jObj, getPropertyType(propertyName)));
		valueIndex++;
	}
	
	private void listValue(StringBuilder sb,JSONObject jObj) throws JSONException{
		String propertyName = jObj.getString(PROPERTY);
		sb.append(propertyName);
		sb.append(jObj.getString(CONDITION));
		sb.append(" (");
		JSONArray arr = jObj.getJSONArray(LISTVALUE);
		int length = arr.length();
		for(int i=0;i<length;i++){
			valueList.add(getValue(arr,getPropertyType(propertyName),i));
			sb.append(VALUE_INDEX+valueIndex);
			sb.append(",");
			valueIndex++;
		}
		sb.deleteCharAt(sb.length()-1);
		sb.append(" )");
		sb.append(" and ");
	}
	
	private void betweenValue(StringBuilder sb,JSONObject jObj) throws JSONException{
		String propertyName = jObj.getString(PROPERTY);
		sb.append(propertyName);
		sb.append(jObj.getString(CONDITION));
		JSONArray arr = jObj.getJSONArray(BETWEENVALUE);
		sb.append(VALUE_INDEX+valueIndex);
		valueList.add(getValue(arr,getPropertyType(propertyName),0));
		valueIndex++;
		sb.append(" and ");
		sb.append(VALUE_INDEX+valueIndex);
		valueList.add(getValue(arr,getPropertyType(propertyName),1));
		valueIndex++;
		sb.append(" and ");
	}
	
	/**
	 * 根据类型获取属性值
	 * @param jObj
	 * @param type
	 * @return
	 * @throws JSONException
	 */
	private Object getValue(JSONObject jObj,String type) throws JSONException{
		if(type.equals("int")||type.equals("Integer")){
			return jObj.getInt(SINGLEVALUE);
		} else if(type.equals("double")||type.equals("float")){
			return jObj.getDouble(SINGLEVALUE);
		} else if(type.equals("long")){
			return jObj.getLong(SINGLEVALUE);
		} else if(type.equals("boolean")){
			return jObj.getBoolean(SINGLEVALUE);
		} else if(type.equals("String")||type.equals("date")){
			return jObj.getString(SINGLEVALUE);
		}
		return null;
	}
	
	private Object getValue(JSONArray jArr,String type,int index) throws JSONException{

		if(type.equals("int")||type.equals("Integer")){
			return jArr.getInt(index);
		} else if(type.equals("double")||type.equals("float")){
			return jArr.getDouble(index);
		} else if(type.equals("long")){
			return jArr.getLong(index);
		} else if(type.equals("boolean")){
			return jArr.getBoolean(index);
		} else if(type.equals("String")||type.equals("date")){
			return jArr.getString(index);
		}
		return null;
	
	}
	
	/**
	 * 获取属性的类型
	 * @param propertyName
	 * @return
	 */
	private String getPropertyType(String propertyName){
		String type = null;
		try {
			type =  PropertyUtils.getPropertyType(unity, propertyName).getSimpleName();
		} catch (IllegalAccessException | InvocationTargetException
				| NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return type;
	}
	
}


